<?php
namespace App\Http\Controllers;

use Carbon\Carbon;
use App\Models\Order;
use App\Events\OrderPaid;
use Endroid\QrCode\QrCode;
use Illuminate\Http\Request;
use App\Exceptions\InvalidRequestException;

class PaymentController extends Controller
{
    public function payByAlipay(Order $order,Request $request) {
        // 判断订单是否属于当前用户
        $this->authorize('own',$order);
        // 订单已支付或者关闭
        if($order->paid_at || $order->closed) {
            throw new InvalidRequestException('订单状态不正确');
        }

        // 调用支付宝的网页支付
        return app('alipay')->web([
            // 订单编号，需保证在商户段不重复
            'out_trade_no' => $order->no,
            // 订单金额，单位 元，支持小数点后两位
            'total_amount' => $order->total_amount,
            // 订单标题
            'subject' => '支付Laravel Shop 的订单:' .$order->no,
        ]);
    }

    // 支付宝前端回调页面
    public function alipayReturn() {
        // 校验提交的参数是否合法
        try {
            app('alipay')->verify();
        } catch(\Exception $e) {
            return view('pages.error',['msg' => '数据不正确']);
        }
        return view('pages.success',['msg' => '付款成功']);
    }

    // 服务器端回调
    public function alipayNotify() {
        // 校验输入参数
        $data = app('alipay')->verify();
        \Log::info('支付宝回传数据:'.$data);
        if($data->trade_status !== 'TRADE_SUCCESS') {
            return 'fail';
        }
        // $data->out_trade_no  拿到订单流水号，并在数据库中查询
        $order = Order::where('no',$data->out_trade_no)->first();
        // 正常来说不太可能出现支付了一笔不存在的订单，这个判断只是加强系统健壮性
        if(!$order) {
            return 'fail';
        }
        // 如果这笔订单的状态已经是已支付
        if($order->paid_at) {
            // 返回数据给支付宝
            return app('alipay')->success();
        }

        $order->update([
            'paid_at'           => Carbon::now(),
            'payment_method'    => 'alipay',
            'payment_no'        => $data->trade_no, // 支付宝订单号
            'closed'            => false,
        ]);

        $this->afterPaid($order);
        return app('alipay')->success();
    }

    // 微信扫码支付
    public function payByWechat(Order $order,Request $request) {
        // 校验权限
        $this->authorize('own',$order);
        // 校验订单状态
        if($order->paid_at || $order->closed) {
            throw new InvalidRequestException('订单状态不正确');
        }

        /*
        // scan 方法为拉起微信扫码支付
        return app('wechat_pay')->scan([
            // 商户订单流水号，与支付宝out_trade_no 一样
            'out_trade_no' => $order->no,
            'total_fee' => $order->total_amount * 100,
            'body'  => '支付Laravel Shop 的订单'.$order->no,
        ]);
        */
        $wechatOrder = app('wechat_pay')->scan([
            // 商户订单流水号，与支付宝out_trade_no 一样
            'out_trade_no' => $order->no,
            'total_fee' => $order->total_amount * 100,
            'body'  => '支付Laravel Shop 的订单'.$order->no,
        ]);
        // 把要转换的字符串作为QrCode 的构造函数参数
        $qrCode = new QrCode($wechatOrder->code_url);
        // 将生成的二维码图片数据以字符串形式输出，并带上相应的响应
        return response($qrCode->writeString(), 200, ['Content-Type' => $qrCode->getContentType()]);
    }

    // 微信服务器回调
    public function wechatNotify() {
        // 校验回调蚕食是否正确
        $data = app('wechat_pay')->verify();
        \Log::info($data);
        if($data->result_code !== 'SUCCESS' || $data->return_code !== 'SUCCESS') {
            return 'fail';
            exit();
        }
        // 找到对应的订单
        $order = Order::where('no',$data->out_trade_no)->first();

        // 订单不存在则告知微信支付
        if(!$order) {
            return 'fail';
        }
        // 订单已支付
        if($order->paid_at) {
            // 告知微信支付此订单已处理
            return app('wechat_pay')->success();
        }

        // 将订单标记为已支付
        $order->update([
            'paid_at' => Carbon::now(),
            'payment_method' => 'wechat',
            'payment_no' => $data->transaction_id,
        ]);

        $this->afterPaid($order);
        return app('wechat_pay')->success();
    }

    // 微信退款回调
    public function wechatRefundNotify() {
        // 给微信的失败响应
        $failXml = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>';
        $data = app('wechat_pay')->verify(null,true);
        //没有找到对应的订单，原则上不可能发生，保证代码健壮性
        if(!$order = Order::where('no',$data['out_trade_no'])->first()) {
            return $failXml;
        }
        if($data['refund_status'] === 'SUCCESS') {
            // 退款成功，将订单退款状态改成退款成功
            $order->update([
                'refund_status' => Order::REFUND_STATUS_SUCCESS,
            ]);
        } else {
            // 退款失败，将具体状态存入extra 字段，并将退款状态改成失败
            $extra = $order->extra;
            $extra['refund_failed_code'] = $data['refund_status'];
            $order->update([
                'refund_status' => Order::REFUND_STATUS_FAILED,
            ]);
        }

        return app('wechat_pay')->success();
    }

    protected function afterPaid(Order $order) {
        // \Log::info('event 事件开始============');
        event(new OrderPaid($order));
    }

}
